/****************************************************************************
 * Copyright (c) 2010 - Quildreen <quildreen@gmail.com>                     *
 *                                                                          *
 * Permission is hereby granted, free of charge, to any person              *
 * obtaining a copy of this software and associated documentation files     *
 * (the "Software"), to deal in the Software without restriction,           *
 * including without limitation the rights to use, copy, modify, merge,     *
 * publish, distribute, sublicense, and/or sell copies of the Software,     *
 * and to permit persons to whom the Software is furnished to do so,        *
 * subject to the following conditions:                                     *
 *                                                                          *
 * The above copyright notice and this permission notice shall be           *
 * included in all copies or substantial portions of the Software.          *
 *                                                                          *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,          *
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF       *
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND                    *
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE   *
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION   *
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION    *
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.          *
 ****************************************************************************/

/**
 * @module    main
 * @author    Quildreen <quildreen@gmail.com>
 *
 * A small Space Invaders clone.
 */


/* imports lily modules */
lily.require("graphics.sprite",   /* sprite management classes */
             "sm.*",              /* state machine and application classes */
             "graphics.dom.anim",    /* DOM surfaces and Animations */
             "input.*");          /* input management */


/* game's main, fired when all required classes are loaded */
lily.onLoad(function() {

    /* global game variables */
    var canvas = new lily.graphics.dom.Surface(null, 600, 444); /* game canvas */
    var clock = new lily.time.Clock(gameLoop, 40); /* game periodic clock */


    /* shorthands for some lily components */
    var Input = lily.input.Manager;
    var consts = lily.input.constants;


    /* installs the input management utilities */
    Input.install('main_window');


    /* installs canvas */
    $("main_window").insert(canvas._canvas);


    var Laser = Class.create(lily.graphics.sprite.Sprite,
    {
        initialize: function($super, groups)
        {
            $super(groups);

            this.surface = new lily.graphics.dom.Surface("gfx/laser.gif");
            this.speed = 0.5;
            this.x = 0;
            this.y = 0;
            this.width = 4;
            this.height = 28;
        },

        die: function($super)
        {
            $super();
            this.surface._canvas.style.display = "none";
        },

        render: function(lag)
        {
            if (this.alive) {
                canvas.blit(this.surface, [this.x, this.y]);
                this.y -= this.speed * lag;

                if (this.y < -this.height || barrier_group.collide([this]) ||
                    alien_group.collide([this], true)) {
                    this.surface._canvas.style.top = "-100px";
                    this.y = -100;
                    this.alive = false;
                }
            }
        }
    });


    /**
     * Main character sprite.
     */
    var Player = Class.create(lily.graphics.sprite.Sprite,
    {
        /**
         * Initializes the player, loads resources needed.
         */
        initialize: function($super, groups)
        {
            $super(groups);

            this.surface = new lily.graphics.dom.Surface("gfx/player.gif");
            this.speed = 0.2;
            this.x = (600 - 28) / 2;
            this.y = 400;
            this.width = 28;
            this.height = 32;

            this.shot = new Laser();
        },

        die: function() {
            this.shot.die();
            clock.stop();
            $("game_over").style.display = "block";
        },

        /**
         * Renders the player ship to the screen
         */
        render: function(lag)
        {
            if (Input.isHeld(consts.K_LEFT)) {
                this.x -= this.speed * lag;
                if (this.x < 10) {
                    this.x = 10;
                }
            } else if (Input.isHeld(consts.K_RIGHT)) {
                this.x += this.speed * lag;
                if (this.x > 600 - 48) {
                    this.x = 600 - 48;
                }
            }
            if (Input.isHeld(consts.K_SPACE)) {
                if (!this.shot.alive) {
                    this.shot.alive = true;
                    this.shot.x = this.x + 12;
                    this.shot.y = this.y - this.shot.height;
                }
            }

            this.shot.render(lag);
            canvas.blit(this.surface, [this.x, this.y]);
        }
    });


    /**
     * Barrier object.
     */
    var Barrier = Class.create(lily.graphics.sprite.Sprite,
    {
        /**
         * Initializes the barrier, load needed resources.
         */
        initialize: function($super, groups, x)
        {
            $super(groups);

            this.surface = new lily.graphics.dom.Surface("gfx/barrier.gif");
            this.x = x;
            this.y = 300;
            this.width = 62;
            this.height = 32;
        },

        /**
         * Render the barrier object.
         */
        render: function(lag)
        {
            canvas.blit(this.surface, [this.x, this.y]);
        }
    });

    var AlienShot = Class.create(lily.graphics.sprite.Sprite,
    {
        initialize: function($super, groups)
        {
            $super(groups);

            this.surface = new lily.graphics.dom.anim.Strip("gfx/alien-shot.gif",
                                   [12, 24], [1, 2], 2);
            this.speed = 0.2;
            this.x = 0;
            this.y = 0;
            this.width = 12;
            this.height = 24;
        },

        die: function($super)
        {
            $super();
            this.surface.surface._canvas.style.display = "none";
        },

        render: function(lag)
        {
            if (this.alive) {
                this.surface.update(lag);
                canvas.blit(this.surface.surface, [this.x, this.y]);
                this.y += this.speed * lag;

                if (this.y > 480 || barrier_group.collide([this]) ||
                    player_group.collide([this], true)) {
                    this.surface.surface._canvas.style.top = "-100px";
                    this.y = -100;
                    this.alive = false;
                }
            }
        }
    });

    var BigAlien = Class.create(lily.graphics.sprite.Sprite,
    {
        initialize: function($super, groups, x)
        {
            $super(groups);

            this.surface = new lily.graphics.dom.anim.Strip("gfx/big-alien.gif",
                               [56, 32], [2, 1], 1);
            this.speed = 0.015;
            this.x = x;
            this.y = 10;
            this.offset = 0;
            this.dir = 1;
            this.width = 56;
            this.height = 32;
            this.skip_frames = 5;
            this.shot = new AlienShot();
        },

        getRect: function()
        {
            return {
                top: this.y,
                left: this.x + this.offset,
                right: this.x + this.offset + this.width,
                bottom: this.y + this.height
            };
        },

        die: function($super)
        {
            $super();
            this.surface.surface._canvas.style.display = "none";
            this.shot.die();
        },

        render: function(lag)
        {
            lag *= 1.5;

            this.offset += this.speed * lag * this.dir;
            if (this.offset > 100 || this.offset < 0) {
                this.dir *= -1;
                this.offset = Math.max(Math.min(100, this.offset), 0);
                this.y += this.height + 10;
            }

            if (!this.shot.alive && Math.random() < 0.01) {
                this.shot.alive = true;
                this.shot.x = this.x + this.offset + 20;
                this.shot.y = this.y + this.height;
            }

            this.shot.render(lag);
            this.surface.update(lag);
            canvas.blit(this.surface.surface, [this.x + this.offset, this.y]);
        }
    });

    var MidAlien = Class.create(BigAlien,
    {
        initialize: function($super, groups, x, y)
        {
            $super(groups, x);
            this.surface = new lily.graphics.dom.anim.Strip("gfx/med-alien.gif",
                               [53, 32], [2, 1], 1);
            this.y = y;
            this.width = 53;
        }
    });

    var SmallAlien = Class.create(MidAlien,
    {
        initialize: function($super, groups, x, y)
        {
            $super(groups, x, y);
            this.surface = new lily.graphics.dom.anim.Strip("gfx/small-alien.gif",
                               [48,32], [2, 1], 1);
            this.width = 48;
        }
    });


    var render_group = new lily.graphics.sprite.SpriteGroup();
    var barrier_group = new lily.graphics.sprite.SpriteGroup();
    var alien_group = new lily.graphics.sprite.SpriteGroup();
    var player_group = new lily.graphics.sprite.SpriteGroup();
    var player = new Player([render_group, player_group]);
    var i;
    var fps_count = $("fps");

    for (i=4; i--; ) {
        var barrier = new Barrier([barrier_group, render_group], i*150+44);
    }

    for (i=6; i--; ) {
        var alien = new BigAlien([alien_group, render_group], i*80+25);
    }

    for (i=6; i--; ) {
        var alien = new MidAlien([alien_group, render_group], i*81+25, 70);
    }

    for (i=12; i--; ) {
        var l = ~~(i / 6),
            c = i % 6;
        var alien = new SmallAlien([alien_group, render_group], c*83+25, l*60+130);
    }



    /**
     * main game loop funtion
     * @method gameLoop(lag)
     *     - {Number} lag: clock latency.
     */
    function gameLoop(lag) {
        Input.update();
        render_group.update(lag);
        fps_count.innerHTML = clock.fps;

        /*
            var fps = App.clock.fps;
	    fps_iter++; total_fps += fps;
            if (!min_fps || fps < min_fps) { min_fps = fps }
            if (fps > max_fps) { max_fps = fps }
            if (fps_iter >= 100) {
                console.log("average fps: " + total_fps/fps_iter + ", " +
                            "minimum fps: " + min_fps + ", " +
                            "maximum fps: " + max_fps);
                fps_iter = total_fps = min_fps = max_fps = 0;
            }*/
    }

    /* start the game */
    clock.start();


/*

    var fps_iter = 0; var total_fps = 0;
    var min_fps = 0;
    var max_fps = 0;
*/
});